package com.jy.datapipeline.importserver.service.impl;

import com.alibaba.excel.exception.ExcelAnalysisStopException;
import com.alibaba.excel.util.ListUtils;
import com.jy.datapipeline.common.util.*;
import com.jy.datapipeline.export.entity.DataSourceInfoModel;
import com.jy.datapipeline.export.service.DataSourceInfoService;
import com.jy.datapipeline.common.constants.ExpConstants;
import com.jy.datapipeline.common.constants.PrefixConstants;
import com.jy.datapipeline.importserver.common.dto.RuleTemplateDto;
import com.jy.datapipeline.importserver.common.enums.impl.*;
import com.jy.datapipeline.common.exception.GlobalException;
import com.jy.datapipeline.common.vo.ReturnVo;
import com.jy.datapipeline.importserver.entity.ImportRule;
import com.jy.datapipeline.importserver.entity.ImportRuleTable;
import com.jy.datapipeline.importserver.mapper.ImportRuleMapper;
import com.jy.datapipeline.importserver.service.*;
import com.jy.datapipeline.importserver.service.strategy.executor.ImportModeExecutor;
import com.jy.datapipeline.importserver.support.ImportRuleSupport;
import com.mysql.cj.util.StringUtils;
import lombok.SneakyThrows;
import org.quartz.SchedulerException;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @类名 ImportRuleServiceImpl
 * @描述 TODO
 * @作者 白条君
 * @创建日期 2023/4/17 10:13
 * @版本 1.0
 */
@Service
public class ImportRuleServiceImpl implements ImportRuleService {

    @Resource
    private ImportRuleMapper importRuleMapper;

    private final ImportRuleTableService importRuleTableService;

    private final ImportTaskService importTaskService;

    private final ImportSqlldrInfoService importSqlldrInfoService;

    private final DataSourceInfoService dataSourceInfoService;

    private final ImportDataSourceService importDataSourceService;

    @Lazy
    public ImportRuleServiceImpl(ImportRuleTableService importRuleTableService,
                                 ImportTaskService importTaskService,
                                 ImportSqlldrInfoService importSqlldrInfoService,
                                 DataSourceInfoService dataSourceInfoService,
                                 ImportDataSourceService importDataSourceService) {
        this.importSqlldrInfoService = importSqlldrInfoService;
        this.importRuleTableService = importRuleTableService;
        this.importTaskService = importTaskService;
        this.dataSourceInfoService = dataSourceInfoService;
        this.importDataSourceService = importDataSourceService;
    }

    @Transactional
    @Override
    public Long addImportRule(ImportRule importRule) throws GlobalException {
        //添加导入规则
        if (StringUtils.isNullOrEmpty(importRule.getRuleName()) || StringUtils.isNullOrEmpty(importRule.getSourceDatabase()) ||
                StringUtils.isNullOrEmpty(importRule.getTargetDatabase()) || StringUtils.isNullOrEmpty(importRule.getSeperator())
                || StringUtils.isNullOrEmpty(importRule.getLoadType()) || StringUtils.isNullOrEmpty(importRule.getSid()) ||
                StringUtils.isNullOrEmpty(importRule.getSqlldrParams()) || StringUtils.isNullOrEmpty(importRule.getImportMode())) {
            throw new GlobalException(ReturnEnum.PARAM_ERROR.getCode(), ExpConstants.PARAMS_EXP);
        }

        Integer isSameName = importRuleMapper.isExistsSameName(importRule.getRuleName());
        if (isSameName != null) {
            throw new GlobalException(ExpConstants.SAME_RULE_NAME_EXP);
        }

        //执行导入并添加sqlldrInfoId
        ImportModeExecutor.execute(importRule);

        if (StringUtils.isNullOrEmpty(importRule.getRuleId())) {
            String ruleId = StringUtil.concat(new StringBuffer(), PrefixConstants.RULE_PREFIX, "_", String.valueOf(SnowFlakeUtil.getNextId()));
            importRule.setRuleId(ruleId);
        }

        importRule.setUpdateTime(DateTimeUtil.getNow());

        int res = importRuleMapper.insertSelective(importRule);
        if (res == 0) {
            throw new GlobalException(ReturnEnum.SERVER_ERROR.getCode(), ExpConstants.ADD_FAIL);
        }
        return importRule.getId();
    }

    @Override
    public ReturnVo queryByPage(Long pageNo, Long pageSize, String ruleId, String sourceDatabase, String targetDatabaseId) {
        List<ImportRule> importRules = importRuleMapper.selectByPage((pageNo - 1) * pageSize, pageSize, ruleId, sourceDatabase, targetDatabaseId);
        for (ImportRule importRule : importRules) {
            importRule.setTargetDatabase(importRule.getTargetDatabase().toUpperCase(Locale.ROOT));
        }
        long totalSize = importRuleMapper.selectTotalSize(ruleId, sourceDatabase, targetDatabaseId);
        long totalPage = PageUtil.getTotalPage(totalSize, pageSize);
        return ReturnVo.ok().put(importRules).put("totalSize", totalSize).put("totalPage", totalPage);
    }

    @Override
    public void modifyRule(ImportRule importRule) throws GlobalException {
        String ruleName = importRule.getRuleName();
        String seperator = importRule.getSeperator();
        String loadType = importRule.getLoadType();

        if (StringUtils.isNullOrEmpty(ruleName) || StringUtils.isNullOrEmpty(seperator) || StringUtils.isNullOrEmpty(loadType)) {
            throw new GlobalException(ReturnEnum.PARAM_ERROR.getCode(), ExpConstants.PARAMS_EXP);
        }

        Integer isSameName = importRuleMapper.isExistsSameName(importRule.getRuleName());
        if (isSameName != null) {
            throw new GlobalException(ExpConstants.SAME_RULE_NAME_EXP);
        }

        //修改导入规则
        importRule.setUpdateTime(DateTimeUtil.getNow());
        int res = importRuleMapper.updateByPrimaryKeySelective(importRule);
        if (res == 0) {
            throw new GlobalException(ReturnEnum.SERVER_ERROR.getCode(), ExpConstants.MODIFY_FAIL);
        }
    }

    @Transactional
    @Override
    public void deleteRule(Long id) throws GlobalException, SchedulerException {
        String ruleId = importRuleMapper.selectRuleIdById(id);

        //删除任务、子任务、任务执行日志
        importTaskService.removeTaskByRuleId(ruleId);

        //删除ruleTable
        List<ImportRuleTable> importRuleTables = importRuleTableService.queryByRuleId(ruleId);
        for (ImportRuleTable importRuleTable : importRuleTables) {
            importRuleTableService.deleteRuleTable(importRuleTable.getId());
        }

        //删除sqlldr
        String sqlldrInfoId = importRuleMapper.selectSqlldrInfoId(id);
        importSqlldrInfoService.deleteSqlldrInfo(sqlldrInfoId);

        //查找rule资源
        Integer resource = importRuleMapper.selectResource(id);
        if (resource == null) {
            throw new GlobalException(ReturnEnum.SERVER_ERROR.getCode(), ExpConstants.RESOURCE_EXP);
        }

        //删除rule
        int res = importRuleMapper.deleteByPrimaryKey(id);
        if (res == 0) {
            throw new GlobalException(ReturnEnum.SERVER_ERROR.getCode(), ExpConstants.DELETE_FAIL);
        }
    }

    @Override
    public List<ImportRule> queryAllNames(String ruleName) {
        return importRuleMapper.selectAllNames(ruleName);
    }

    @Override
    public ImportRule selectImportRule(String ruleId) {
        return importRuleMapper.selectSqlldrInfoIdByRuleId(ruleId);
    }

    @Override
    public void modifyImportRuleUpdateTime(ImportRule importRule) throws GlobalException {
        int res = importRuleMapper.updateImportRuleUpdateTime(importRule);
        if (res == 0) {
            throw new GlobalException(ExpConstants.MODIFY_FAIL);
        }
    }

    @Override
    public ImportRule queryOneByRuleName(String ruleName) {
        return importRuleMapper.selectOneByRuleName(ruleName);
    }

    private void notNullCheck(RuleTemplateDto ruleTemplateDto) {
        AssertUtil.isNull(ruleTemplateDto.getRuleName(), ExpConstants.RULE_NAME_NOT_NULL);
        AssertUtil.isNull(ruleTemplateDto.getSourceDatabase(), ExpConstants.SOURCE_DATABASE_NOT_NULL);
        AssertUtil.isNull(ruleTemplateDto.getTargetDatabase(), ExpConstants.TARGET_DATABASE_NOT_NULL);
        AssertUtil.isNull(ruleTemplateDto.getSeperator(), ExpConstants.SEPERATOR_NOT_NULL);
        AssertUtil.isNull(ruleTemplateDto.getLoadType(), ExpConstants.LOAD_TYPE_NOT_NULL);
        AssertUtil.isNull(ruleTemplateDto.getImportMode(), ExpConstants.IMPORT_MODE_NOT_NULL);
        AssertUtil.isNull(ruleTemplateDto.getSid(), ExpConstants.SID_NOT_NULL);
        AssertUtil.isNull(ruleTemplateDto.getSqlldrParams(), ExpConstants.SQLLDR_NOT_NULL);
        AssertUtil.isNull(ruleTemplateDto.getSourceSchema(), ExpConstants.SOURCE_SCHEMA_NOT_NULL);
        AssertUtil.isNull(ruleTemplateDto.getSourceTableName(), ExpConstants.SOURCE_TABLE_NAME_NOT_NULL);
        AssertUtil.isNull(ruleTemplateDto.getTargetSchema(), ExpConstants.TARGET_SCHEMA_NOT_NULL);
        AssertUtil.isNull(ruleTemplateDto.getTargetTableName(), ExpConstants.TARGET_TABLE_NAME_NOT_NULL);
        AssertUtil.isNull(ruleTemplateDto.getTargetColumnList(), ExpConstants.TARGET_COLUMN_NOT_NULL);
        AssertUtil.isNull(ruleTemplateDto.getIsDynamicTable(), ExpConstants.TARGET_TABLE_TYPE_NOT_NULl);
    }

    @SneakyThrows
    @Override
    public <T> T analysisExcelRows(T data) {
        RuleTemplateDto ruleTemplateDto = (RuleTemplateDto) data;

        //非空校验
        this.notNullCheck(ruleTemplateDto);

        //校验规则名称唯一性
        Integer existsSameName = this.importRuleMapper.isExistsSameName(ruleTemplateDto.getRuleName());
        AssertUtil.isNotNUll(existsSameName, ExpConstants.SAME_RULE_NAME_EXP);

        //分隔符校验
        String seperator = ruleTemplateDto.getSeperator();
        if (StringUtil.isNumberOrChinese(seperator)) {
            throw new ExcelAnalysisStopException(ExpConstants.SEPERATOR_CONSTRAINT_EXP);
        }

        //校验导入方式是否是1或者0
        if (!String.valueOf(LoadTypeEnum.APPEND.getCode()).equals(ruleTemplateDto.getLoadType()) &&
                !String.valueOf(LoadTypeEnum.TRUNCATE.getCode()).equals(ruleTemplateDto.getLoadType())) {
            throw new ExcelAnalysisStopException(ExpConstants.LOAD_TYPE_CONSTRAINT_EXP);
        }

        //校验sqlldr导入模式是不是1
        if(!String.valueOf(ImportModeEnum.SQLLDR_TOOL_MODE.getCode()).equals(ruleTemplateDto.getImportMode())) {
            throw new ExcelAnalysisStopException(ExpConstants.IMPORT_MODE_CONSTRAINT_EXP);
        }

        //校验动态表规则是否是0或者1
        boolean isDynamicTable = String.valueOf(DynamicTableEnum.DYNAMIC.getCode()).equals(ruleTemplateDto.getIsDynamicTable());
        if (!isDynamicTable && !String.valueOf(DynamicTableEnum.NOT_DYNAMIC.getCode()).equals(ruleTemplateDto.getIsDynamicTable())) {
            throw new ExcelAnalysisStopException(ExpConstants.DYNAMIC_TABLE_CONSTRAINT_EXP);
        }

        //如果是动态表则规则和函数值不能为空，且动态规则只能是ADDMONTHS
        if (isDynamicTable) {
            AssertUtil.isNull(ruleTemplateDto.getDynamicTableRule(), ExpConstants.TARGET_TABLE_DYNAMIC_RULE_NOT_NULL);
            if (!DynamicTableRuleEnum.ADDMONTHS.getMsg().equals(ruleTemplateDto.getDynamicTableRule())) {
                throw new ExcelAnalysisStopException(ExpConstants.DYNAMIC_TABLE_RULE_CONSTRAINT_EXP);
            }
            AssertUtil.isNull(ruleTemplateDto.getDynamicTableRuleValue(), ExpConstants.FUN_VALUE_NOT_NULL);
            if (!StringUtil.isNumber(ruleTemplateDto.getDynamicTableRuleValue())) {
                throw new ExcelAnalysisStopException(ExpConstants.FUN_VALUE_CONSTRAINT_EXP);
            }
        }

        //城市编码只能是数值格式
        if (!StringUtil.isNumber(ruleTemplateDto.getCityCode())) {
            throw new ExcelAnalysisStopException(ExpConstants.CITY_CODE_CONSTRAINT_EXP);
        }

        //校验目标数据源是否存在
        DataSourceInfoModel dataSourceInfoModel = dataSourceInfoService.findByDataSourceName(ruleTemplateDto.getTargetDatabase());
        AssertUtil.isNull(dataSourceInfoModel, ExpConstants.TARGET_DATASOURCE_NOT_EXIST_EXP);
        String dataSourceId = dataSourceInfoModel.getDataSourceId();
        ruleTemplateDto.setDataSourceId(dataSourceId);

        //解析字段
        try {
            List<Map<String, Object>> columns = importDataSourceService.queryDataSourceColumns(dataSourceId, ruleTemplateDto.getTargetSchema(), ruleTemplateDto.getTargetTableName());
            List<ImportRuleTable.ImportColumn> importColumns = ImportRuleSupport.generateImportColumnList(ruleTemplateDto, columns);
            String targetColumnList = ImportRuleSupport.listConvertString(importColumns);
            ruleTemplateDto.setTargetColumnList(targetColumnList);
        } catch (Exception e) {
            throw new ExcelAnalysisStopException(ExpConstants.COLUMN_ANALYSIS_EXP);
        }

        return (T) ruleTemplateDto;
    }

    @Transactional
    @Override
    public <T> Set<Long> batchSave(List<T> t) {
        List<ImportRule> importRuleList = ListUtils.newArrayList();
        List<ImportRuleTable> importRuleTableList = ListUtils.newArrayList();

        List<RuleTemplateDto> ruleTemplateDtoList = ConvertUtil.convertArray(t, RuleTemplateDto.class);
        ImportRule importRule;
        ImportRuleTable importRuleTable;
        String dataSourceId;
        String ruleId;
        for (RuleTemplateDto ruleTemplateDto : ruleTemplateDtoList) {
            importRule = new ImportRule();
            ruleId = PrefixConstants.RULE_PREFIX + "_" + SnowFlakeUtil.getNextId();
            importRule.setRuleId(ruleId);
            dataSourceId = ruleTemplateDto.getDataSourceId();
            importRule.setDataSourceId(dataSourceId);
            BeanUtils.copyProperties(ruleTemplateDto, importRule);

            //执行导入并添加sqlldrInfoId
            ImportModeExecutor.execute(importRule);

            importRule.setUpdateTime(new Date());
            importRuleList.add(importRule);

            importRuleTable = new ImportRuleTable();
            importRuleTable.setRuleTableId(PrefixConstants.RULE_TABLE_PREFIX + "_" + SnowFlakeUtil.getNextId());
            importRuleTable.setRuleId(ruleId);
            importRuleTable.setDataSourceId(dataSourceId);
            String ruleValue = ruleTemplateDto.getDynamicTableRuleValue();
            if (dm.jdbc.util.StringUtil.isNotEmpty(ruleValue)) {
                importRuleTable.setDynamicTableRuleValue(Integer.valueOf(ruleValue));
            }
            BeanUtils.copyProperties(ruleTemplateDto, importRuleTable);
            importRuleTableList.add(importRuleTable);
        }

        int importRuleSize = importRuleMapper.batchInsert(importRuleList);
        AssertUtil.totalAffectedRows(importRuleSize, ruleTemplateDtoList, ExpConstants.BATCH_ADD_FAIL);

        int importRuleTableSize = importRuleTableService.batchAdd(importRuleTableList);
        AssertUtil.totalAffectedRows(importRuleTableSize, importRuleTableList, ExpConstants.BATCH_ADD_FAIL);
        return importRuleList.stream().map(ImportRule::getId).collect(Collectors.toSet());
    }

    @Transactional
    @Override
    public <T> Long save(T t) {
        RuleTemplateDto ruleTemplateDto = (RuleTemplateDto) t;
        String dataSourceId = ruleTemplateDto.getDataSourceId();

        //添加导入规则
        ImportRule importRule = new ImportRule();
        String ruleId = PrefixConstants.RULE_PREFIX + "_" + SnowFlakeUtil.getNextId();
        importRule.setRuleId(ruleId);
        importRule.setDataSourceId(dataSourceId);
        BeanUtils.copyProperties(t, importRule);
        //执行导入并添加sqlldrInfoId
        ImportModeExecutor.execute(importRule);
        importRule.setUpdateTime(new Date());
        Long id = this.addImportRule(importRule);

        //添加导入规则详情
        ImportRuleTable importRuleTable = new ImportRuleTable();
        importRuleTable.setRuleTableId(PrefixConstants.RULE_TABLE_PREFIX + "_" + SnowFlakeUtil.getNextId());
        importRuleTable.setRuleId(ruleId);
        importRuleTable.setDataSourceId(dataSourceId);
        String ruleValue = ruleTemplateDto.getDynamicTableRuleValue();
        if (dm.jdbc.util.StringUtil.isNotEmpty(ruleValue)) {
            importRuleTable.setDynamicTableRuleValue(Integer.valueOf(ruleValue));
        }
        BeanUtils.copyProperties(t, importRuleTable);
        importRuleTableService.add(importRuleTable);
        return id;
    }

    @Transactional
    @Override
    public void batchDelete(Set<Long> ids) {
        //获取id关联的ruleid和sqlldrid
        List<ImportRule> importRuleList = importRuleMapper.selectRuleIdsByIds(ids);
        Set<String> ruleIds = importRuleList.stream().map(ImportRule::getRuleId).collect(Collectors.toSet());
        Set<String> sqlldrInfoIds = importRuleList.stream().map(ImportRule::getSqlldrInfoId).collect(Collectors.toSet());

        //批量删除子规则
        importRuleTableService.batchRemove(ruleIds);

        //批量删除sqlldr信息
        importSqlldrInfoService.batchRemove(sqlldrInfoIds);

        //批量删除规则
        int size = importRuleMapper.batchDelete(ids);
        AssertUtil.totalAffectedRows(size, ids, ExpConstants.BATCH_DELETE_FAIL);
    }
}
